package models

import (
	"GoAdmin/utils"
	"errors"
	"fmt"
	"log"
	"strings"
	"time"
	"xorm.io/builder"
)

type Student struct {
	Id               int64     `xorm:"not null pk autoincr comment('自增主键') INT(11)"`
	UserId           int       `xorm:"not null comment('用户id外键关联dts_user中的id') index INT(11)"`
	SchoolId         int       `form:"school_id" xorm:"not null comment('驾校id即dts_school中的id') index INT(11)"`
	IcId             int       `xorm:"default 0 comment('IC卡id,学员可以没有IC卡也可以拥有多张IC卡，当前为生效IC卡id') INT(11)"`
	FingerId         int       `xorm:"default 0 comment('指纹id，学员可以拥有多个指纹记录，当前为生效指纹id') INT(11)"`
	PortraitId       int       `xorm:"default 0 comment('头像id，学员可以拥有多个头像记录，当前为生效头像id') INT(11)"`
	LicenceNumber    string    `xorm:"default '' comment('驾驶证号') VARCHAR(32)" form:"licence_number"`
	LicenceGrantDate time.Time `xorm:"comment('驾驶证初领日期 YYYYMMDD') DATE"`
	SignInTime       time.Time `xorm:"not null comment('报名时间 YYYYMMDD') index DATE"`
	OperationStatus  string    `xorm:"default '0' comment('业务类型 0:初领 1:增领 9:其他') ENUM('0','1','9')" form:"operation_status"`
	DrivingCarType   string    `xorm:"default 'C1' comment('原准驾车型') ENUM('A1','A2','A3','B1','B2','C1','C2','C3','C4','C5','D','E','F','M','N','P')" form:"driving_car_type"`
	TrainingCarType  string    `xorm:"default 'C1' comment('培训车型') ENUM('A1','A2','A3','B1','B2','C1','C2','C3','C4','C5','D','E','F','M','N','P')" form:"training_car_type"`
	Status           string    `xorm:"default '0' comment('学员学习进度状态，0：已报名，1234：科目一二三四，5：停止练车（处罚）,6：已结业') ENUM('0','1','2','3','4','5','6')" form:"status"`
	ApprovalStatus   string    `xorm:"default '0' comment('学员提交运管审核状态，0:待审核，1:通过审核，2:未通过审核') ENUM('0','1','2')" form:"approval_status"`
	RecordStatus     string    `xorm:"not null default '0' comment('备案状态 0:未备案 1:已备案') ENUM('0','1')"`
	InstitutionCode  string    `xorm:"comment('运管统一编号') index VARCHAR(16)"`
	LoginStatus      string    `xorm:"default '0' comment('0:登出状态  1：登录状态') ENUM('0','1')"`
	AcrossRecord     string    `xorm:"comment('0:正常    1：跨培训机构备案') ENUM('0','1')"`
	TotalMoney       int       `xorm:"not null default 0 comment('总缴费') INT(11)"`
	PayMoney         int       `xorm:"default 0 comment('已经交费') INT(11)"`
	PayStatus        int       `xorm:"default 0 comment('缴费状态0-未交费1-缴费未全2-已缴费') INT(11)"`
	CharstandardId   int       `xorm:"not null default 0 comment('收费方式id') INT(11)"`
	Frozentime       time.Time `xorm:"comment('冻结时间（用于重复消单的）') DATETIME"`
	Unfrozentime     time.Time `xorm:"comment('解冻时间（用于重复消单的）') DATETIME"`
	CoachId          int       `xorm:"not null default 0 comment('关联coach表id教练表id') index INT(11)"`
	Remainhours1     int64     `xorm:"default 0 comment('该学员剩余可练科目一学时') INT(11)"`
	Remainhours2     int64     `xorm:"default 0 comment('该学员剩余可练科目二学时') INT(11)"`
	Remainhours3     int64     `xorm:"default 0 comment('该学员剩余可练科目三学时') INT(11)"`
	Remainhours4     int64     `xorm:"default 0 comment('该学员剩余可练科目四学时') INT(11)"`
	Remark           string    `xorm:"VARCHAR(255)"`
	Isused           string    `xorm:"default '1' comment('0  已删除 1在使用') ENUM('0','1')"`
	Addtime          time.Time `xorm:"DATETIME created"`
	Reason           string    `xorm:"comment('审核未通过的原因') MEDIUMTEXT"`
	Subject1isreport string    `xorm:"default '0' comment('阶段学时第一部分是否上报') ENUM('0','1')"`
	Subject2isreport string    `xorm:"default '0' comment('阶段学时2是否上报') ENUM('0','1')"`
	Subject3isreport string    `xorm:"default '0' comment('阶段学时3是否上报') ENUM('0','1')"`
	Subject4isreport string    `xorm:"default '0' comment('阶段学时4是否上报') ENUM('0','1')"`
	Portrait_code    string    `xorm:"-"`
	Finger_code      string    `xorm:"-"`
	Portrait_url     string    `xorm:"-"`
	Finger_url       string    `xorm:"-"`
	Content          string    `xorm:"-"`
	Fileid           string    `xorm:"-"`
	PdfUrl           string    `xorm:"varchar(255) default('') " form:"pdf_url"`
	IsImport         int       `xorm:"default(0) comment('是否导入车学堂0未导入1已导入')"`
	CompleteCode     string    `xorm:"varchar(30)"`
	Istransfer       string    `xorm:""  form:"istransfer"`
}

type SchoolStudentList struct {
	Id              int    `json:"id"`
	Name            string `json:"name"`
	Sex             string `json:"sex"`
	Phone           string `json:"phone"`
	IdNumber        string `json:"id_number"`
	Addtime         string `json:"addtime"`
	TrainingCarType string `json:"training_car_type"`
	OperationStatus string `json:"operation_status"`
	CreateTime      string `json:"create_time"`
	BeforeNumber    int    `json:"before_number"`
	ChangeStatus    int    `json:"change_status"`
}

type DownStudent struct {
	Name             string `json:"name"`
	Sex              string `json:"sex"`
	Phone            string `json:"phone"`
	Address          string `json:"address"`
	Nationality      string `json:"nationality"`
	IdType           string `json:"id_type"`
	IdNumber         string `json:"id_number"`
	OperationStatus  string `json:"operation_status"`
	LicenceNumber    string `json:"licence_number"`
	LicenceGrantDate string `json:"licence_grant_date"`
	DrivingCarType   string `json:"driving_car_type"`
	TrainingCarType  string `json:"training_car_type"`
	SignInTime       string `json:"sign_in_time"`
	InstitutionCode  string `json:"institution_code"`
	ImageUrl         string `json:"image_url"`
	FigureUrl        string `json:"figure_url"`
	ChargeMode       string `json:"charge_mode"`
	ClassName        string `json:"class_name"`
	Status           string `json:"status"`
}

func (s *Student) GetDownStudent(filter builder.Cond) (list []*DownStudent, err error) {
	if err = engine.Table("dts_student").Alias("c").Select("c.licence_number,c.licence_grant_date,c.driving_car_type,c.status,c.institution_code,c.training_car_type,c.operation_status,c.sign_in_time,dcs.charge_mode,u.address,u.name,u.nationality,u.id_type,u.phone,u.sex,u.id_number,df.image_url as FigureUrl,dp.image_url,dcs.class_name").Join("LEFT", []string{"dts_user", "u"}, "c.user_id=u.id").
		Join("LEFT", []string{"dts_finger", "df"}, "c.finger_id=df.id").
		Join("LEFT", []string{"dts_portrait", "dp"}, "c.portrait_id=dp.id").
		Join("LEFT", []string{"dts_char_standard", "dcs"}, "c.charstandard_id=dcs.id").
		Where("c.isused=?", "1").And(filter).Desc("c.id").Find(&list); err != nil {
		log.Println(err)
		return list, err
	}
	for k, _ := range list {
		list[k].Phone = strings.Replace(list[k].Phone, "t", "", -1)
		list[k].IdNumber = strings.Replace(list[k].IdNumber, "t", "", -1)
		if list[k].OperationStatus == "0" {
			list[k].DrivingCarType = ""
		}
	}
	return list, nil
}

func (c *Student) GetRelieveList(school_id string, pagesize, offset int) (count int64, list []*SchoolStudentList, err error) {
	err = engine.Table("dts_stu_unregister_record").Alias("sud").
		Select("st.id,u.name,u.sex,u.remark as phone,u.reid_number as id_number,st.addtime,st.training_car_type,st.operation_status,sud.create_time,sud.before_number,sud.change_status").
		Join("left", []string{"dts_student", "st"}, "st.id = sud.student_id").
		Join("left", []string{"dts_user", "u"}, "u.id = st.user_id").
		Where("st.school_id = ? ", school_id).
		Limit(pagesize, offset).
		Desc("sud.id").
		Find(&list)
	count, _ = engine.Table("dts_stu_unregister_record").Alias("sud").
		Join("left", []string{"dts_student", "st"}, "st.id = sud.student_id").
		Join("left", []string{"dts_user", "u"}, "u.id = st.user_id").
		Where("st.school_id = ? ", school_id).
		Desc("sud.id").
		Count()
	//log.Println(err)
	return
}

func (c *Student) GetUnStudentList(school_id string, filter builder.Cond, pagesize, offset int) (count int64, list []*SchoolStudentList, err error) {
	err = engine.Table("dts_student").Alias("st").
		Select("st.id,u.name,u.sex,u.phone,st.addtime,st.training_car_type,st.operation_status,st.isused").
		Join("left", []string{"dts_user", "u"}, "u.id = st.user_id").
		Where("st.school_id = ? ", school_id).
		And(filter).
		Limit(pagesize, offset).Find(&list)
	count, _ = engine.Table("dts_student").Alias("st").
		Join("left", []string{"dts_user", "u"}, "u.id = st.user_id").
		Where("st.school_id = ? ", school_id).
		And(filter).
		Count()
	return
}

type StudentInformation struct {
	Id              int    `json:"id"`
	SchoolId        int    `json:"school_id"`
	SchoolUser      int    `json:"school_user"`
	Province        string `json:"province"`
	City            string `json:"city"`
	Name            string `json:"name"`
	Sex             string `json:"sex"`
	Phone           string `json:"phone"`
	IdNumber        string `json:"id_number"`
	Addtime         string `json:"addtime"`
	SignInTime      string `json:"sign_in_time"`
	TrainingCarType string `json:"training_car_type"`
	RecordStatus    string `json:"record_status"`
	Isused          string `json:"isused"`
	SchoolName      string `json:"school_name"`
	OperationStatus string `json:"operation_status"`
	Istransfer      string `json:"istransfer"`
}

func (c *Student) GetStudentByFilter(filter builder.Cond, pagesize, offset int) (count int64, list []*StudentInformation, err error) {
	err = engine.Table("dts_student").Alias("st").
		Select("st.id,st.school_id,sl.user_id as school_user,sl.province,sl.city,u.name,u.phone,u.sex,u.id_number,sl.name_short as school_name,st.istransfer,st.sign_in_time,st.addtime,st.training_car_type,st.operation_status,st.record_status").
		Join("left", []string{"dts_user", "u"}, "u.id = st.user_id").
		Join("left", []string{"dts_school", "sl"}, "sl.id = st.school_id").
		And(filter).Limit(pagesize, offset).Desc("st.id").Find(&list)
	count, err = engine.Table("dts_student").Alias("st").
		Join("left", []string{"dts_user", "u"}, "u.id = st.user_id").
		Join("left", []string{"dts_school", "sl"}, "sl.id = st.school_id").
		And(filter).Count()
	return
}

type StudentDetailInfo struct {
	Name             string `json:"name"`
	Sex              string `json:"sex"`
	Address          string `json:"address"`
	Birthday         string `json:"birthday"`
	Nation           string `json:"nation"`
	Nationality      string `json:"nationality"`
	IdNumber         string `json:"id_number"`
	Phone            string `json:"phone"`
	Password         string `json:"password"`
	Isused           string `json:"isused"`
	LicenceNumber    string `json:"licence_number"`
	LicenceGrantDate string `json:"licence_grant_date"`
	SignInTime       string `json:"sign_in_time"`
	OperationStatus  string `json:"operation_status"`
	DrivingCarType   string `json:"driving_car_type"`
	TrainingCarType  string `json:"training_car_type"`
	InstitutionCode  string `json:"institution_code"`
	Addtime          string `json:"addtime"`
	RecordStatus     string `json:"record_status"`
	Istransfer       string `json:"istransfer"`
	HeadUrl          string `json:"head_url"`
}

func (c *Student) GetStudentDetailInfo(studentId string) (has bool, list StudentDetailInfo, err error) {
	has, err = engine.Table("dts_student").Alias("st").
		Select("u.name,u.phone,u.sex,u.id_number,u.address,u.nation,u.nationality,u.password,p.image_url as head_url,st.isused,st.driving_car_type,st.licence_number,st.licence_grant_date,st.sign_in_time,st.addtime,st.training_car_type,st.operation_status,st.record_status,st.institution_code,st.istransfer").
		Join("left", []string{"dts_user", "u"}, "u.id = st.user_id").
		Join("left", []string{"dts_portrait", "p"}, "p.id = st.portrait_id").
		Where("st.id = ?", studentId).Get(&list)
	//log.Println(list, err)
	return
}

func (c *Student) Update(id string, fields ...string) bool {
	var (
		err error
	)
	_, err = engine.Table("dts_student").Where("id = ?", id).Cols(fields...).Update(c)
	if err != nil {
		return false
	}
	return true
}

func (c *Student) GetStudentById(id string) (has bool, list Student, err error) {
	has, err = engine.Table("dts_student").
		Where("id = ?", id).Get(&list)
	//log.Println(list, err)
	return
}

func (c *Student) Edit(fields ...string) bool {
	var (
		err error
	)
	_, err = engine.Table("dts_student").Id(c.Id).Cols(fields...).Update(c)
	log.Println(err)
	if err != nil {
		return false
	}
	return true
}

func (c *Student) GetStudentInfoByNum(num string) (stu Student, err error) {
	_, err = engine.Table("dts_student").Alias("st").
		Select("st.id,st.school_id").
		Join("left", []string{"dts_user", "user"}, "st.user_id=user.id").
		Where("user.id_number=? and type= ?", num, "4").Get(&stu)
	//log.Println(err)
	return stu, err
}

type StudentFace struct {
	StudentId int
	Face      string
}

func (c *Student) GetStudentFaceByNum(num string) (stu StudentFace, err error) {
	_, err = engine.Table("dts_student").Alias("st").
		Select("st.id as student_id,p.image_url as face").
		Join("left", []string{"dts_user", "user"}, "st.user_id=user.id").
		Join("left", []string{"dts_portrait", "p"}, "st.portrait_id=p.id").
		Where("user.id_number=? and type= ?", num, "4").Get(&stu)
	return stu, err
}

func (s *Student) GetStudengCodeByPhone(phone string) (code string, err error) {
	if ok := utils.ExistsKey("student:phone:" + phone); ok == false {
		fmt.Println("no exit")
		if _, err := engine.Table(s).Alias("s").
			Select("s.institution_code as code").
			Join("left", []string{"dts_user", "u"}, "s.user_id=u.id").
			Where("u.phone=?", phone).Get(&code); err != nil {
			return "", err
		}
		if err := utils.SetRedisExpire("student:phone:"+phone, code, 6*60*60); err != nil {
			return "", err
		}
		return code, nil
	}
	data, err := utils.GetRedis("student:phone:" + phone)
	if err != nil {
		return "", err
	}
	return string(data), nil

}

// StudentDetail 学员详情得获取
type StudentDetail struct {
	SchoolId int
	Name     string
	Phone    string
	Number   string
	CarType  string
}

// GetStudentDetailByNumber get student detail by number
func GetStudentDetailByNumber(number string) (student StudentDetail, err error) {
	if _, err := engine.Table("dts_student").Alias("s").
		Select("s.school_id,s.training_car_type as car_type,user.name,user.phone,user.id_number as number").
		Join("left", []string{"dts_user", "user"}, "s.user_id=user.id").
		Where("user.phone=?", number).Get(&student); err != nil {
		return student, err
	}
	return student, nil
}

func (s *Student) GetOneStudent(student_id string) (has bool, student Student, err error) {
	has, err = engine.Table("dts_student").ID(student_id).Get(&student)
	return has, student, err
}

type FutureGraduationStudent struct {
	Id                int64
	Name              string
	OperationStatus   string
	Id_number         string
	Phone             string
	Sign_in_time      string
	Training_car_type string
}

func (s *Student) GetFutureGraduation(school_id string, filter builder.Cond, pagesize, offset int) (list []*FutureGraduationStudent, err error, count int64) {
	err = engine.Table("dts_student").Alias("st").
		Select("st.id,ur.name,ur.phone,st.sign_in_time,st.training_car_type,st.operation_status,ur.id_number").
		Join("LEFT", []string{"dts_user", "ur"}, "st.user_id = ur.id").
		Where("st.school_id = ? and st.isused = ?", school_id, "1").
		And(filter).
		Desc("st.id").
		Limit(pagesize, offset).
		Find(&list)
	count, err = engine.Table("dts_student").Alias("st").
		Join("LEFT", []string{"dts_user", "ur"}, "st.user_id = ur.id").
		Where("st.school_id = ? and st.isused = ?", school_id, "1").
		And(filter).
		Count()
	return list, err, count
}

type SS struct {
	SchoolId        int
	Name            string
	Phone           string
	IdNumber        string
	TrainingCarType string
	Image           string
	SignInTime      string
	District        string
}

func (s *Student) GetStudentSchool(id string) (ok bool, student SS, err error) {
	ok, err = engine.Table("dts_student").Alias("s").
		Select("s.school_id,user.name,user.phone,s.sign_in_time,user.id_number,s.training_car_type,p.image_url as image,l.district").
		Join("left", []string{"dts_user", "user"}, "s.user_id=user.id").
		Join("left", []string{"dts_portrait", "p"}, "s.portrait_id=p.id").
		Join("left", []string{"dts_school", "l"}, "l.id=s.school_id").
		Where("s.id = ? and s.isused = ?", id, "1").
		Get(&student)
	log.Println(err)
	return ok, student, err
}

type OpenApiStudentInfo struct {
	JxJc      string `json:"jx_jc"`      //驾校简称
	Name      string `json:"name"`       // 姓名
	IdNum     string `json:"id_num"`     // 身份证号
	Phone     string `json:"phone"`      // 手机号
	Pic       string `json:"pic"`        // 学员头像
	StudentId int    `json:"student_id"` // 学员id
	StuNum    string `json:"stu_num"`    // 学员编号
	TrainType string `json:"train_type"` // 培训车型
	Province  string `json:"province"`
	City      string `json:"city"`
}

func (s *Student) GetOpenApiStudentDetail(idCard string) (list OpenApiStudentInfo, err error) {
	_, err = engine.Table("dts_student").Alias("s").
		Select("s.id as student_id,l.province,l.city,s.institution_code as stu_num,l.name_short as jx_jc,u.name,u.phone,u.id_number as id_num,s.training_car_type as train_type,p.image_url as pic").
		Join("LEFT", []string{"dts_user", "u"}, "u.id=s.user_id").
		Join("LEFT", []string{"dts_school", "l"}, "l.id=s.school_id").
		Join("LEFT", []string{"dts_portrait", "p"}, "p.id=s.portrait_id").
		Where("u.id_number = ?", idCard).Get(&list)
	log.Println(err)
	return
}

// TheoryStudent 理论学员信息
type TheoryStudent struct {
	StudentId       int    `json:"student_id"`
	SchoolId        int    `json:"school_id"`
	SchoolName      string `json:"school_name"`
	SchoolCode      string `json:school_code`
	StudentName     string `json:"student_name"`
	StuCode         string `json:"stu_code"`
	Sex             string `json:"sex"`
	IdNumber        string `json:"id_number"`
	IdType          string `json:"id_type"`
	Address         string `json:"address"`
	Phone           string `json:"phone"`
	TrainingCarType string `json:"training_car_type"`
	OperationStatus string `json:"operation_status"`
	Status          string `json:"status"`
	ApprovalStatus  string `json:"approval_status"`
	RecordStatus    string `json:"record_status"`
	Province        string `json:"province"`
	City            string `json:"city"`
}

// GetSimulatorStudentCacheData get simulator student cache data
func GetSimulatorStudentCacheData(phone string) (data map[string]interface{}, err error) {
	var student TheoryStudent
	if has, err := engine.Table("dts_student").Alias("s").
		Select("s.id as student_id,s.school_id,sch.name_short as school_name,sch.institution_code as school_code,u.name as student_name,s.institution_code as stu_code,u.sex,u.id_number,u.id_type,u.address,u.phone,s.training_car_type,s.operation_status,s.status,s.approval_status,s.record_status").
		Join("left", []string{"dts_user", "u"}, "s.user_id=u.id").
		Join("left", []string{"dts_school", "sch"}, "s.school_id=sch.id").
		Where("u.phone=?", phone).Get(&student); !has || err != nil {
		return data, errors.New("未查询到学员相关信息")
	}
	data = map[string]interface{}{
		"student_id":        student.StudentId,
		"school_id":         student.SchoolId,
		"school_name":       student.SchoolName,
		"school_code":       student.SchoolCode,
		"student_name":      student.StudentName,
		"stu_code":          student.StuCode,
		"sex":               student.Sex,
		"id_number":         student.IdNumber,
		"id_type":           student.IdType,
		"address":           student.Address,
		"phone":             student.Phone,
		"training_car_type": student.TrainingCarType,
		"operation_status":  student.OperationStatus,
		"status":            student.Status,
		"approval_status":   student.ApprovalStatus,
		"record_status":     student.RecordStatus,
		"class":             time.Now().Format("01021504"),
	}
	return data, nil
}

type SubjectLearn struct {
	Id            int
	LastingMinute int
	Mileage       float64
	StartTime     time.Time
	Sn            string
	Isreport      string
	Subject       string
	Type          string
	Iscongye      string
	Iskaohe       string
	Course        string
}

type StudentUserPortrait struct {
	Id               int
	Name             string
	Sex              string
	IdType           string
	IdNumber         string
	Address          string
	Phone            string
	SignInTime       time.Time
	SchoolCode       string
	InstitutionCode  string
	TrainingCarType  string
	OperationStatus  string
	ImageUrl         string
	Zhangurl         string
	SchoolName       string
	SchoolId         int
	CompleteCode     string
	Istransfer       string
	City             string
	Xiaozhangsignurl string
	Addtime          time.Time
	District         string
}

// GetStudentUserById 通过学员id获取学员的详细信息
func (s *Student) GetStudentUserById(id int) (student StudentUserPortrait, err error) {
	if _, err = engine.Table("dts_student").Alias("st").
		Select("st.id,st.institution_code,sl.institution_code as school_code,st.addtime,sl.district,st.training_car_type,st.operation_status,st.complete_code,user.name,user.sex,user.id_type,user.id_number,user.address,user.phone,st.sign_in_time,p.image_url,sl.city,sl.name as school_name, sl.zhangurl, sl.xiaozhangsignurl,st.istransfer").
		Join("INNER", []string{"dts_user", "user"}, "st.user_id=user.id").
		Join("RIGHT", []string{"dts_portrait", "p"}, "st.portrait_id=p.id").
		Join("INNER", []string{"dts_school", "sl"}, "st.school_id=sl.id").
		Where("st.id=? and st.isused = ?", id, "1").
		Get(&student); err != nil {
		return student, err
	}
	return student, nil

}
